{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pickle\n",
    "import operator\n",
    "main_path = '/content/drive/My Drive/Colab Notebooks/'\n",
    "eng = np.load('pad_eng.npy')\n",
    "cns = np.load('pad_cns.npy')\n",
    "cns_o = np.load('cns_o.npy', allow_pickle=True)\n",
    "with open('vocab_bag.pkl', 'rb') as f:\n",
    "    words = pickle.load(f)\n",
    "with open('pad_word_to_index.pkl', 'rb') as f:\n",
    "    word_to_index = pickle.load(f)\n",
    "with open('pad_index_to_word.pkl', 'rb') as f:\n",
    "    index_to_word = pickle.load(f)\n",
    "vocab_size = len(word_to_index) + 1\n",
    "maxLen=20\n",
    "def get_file_list(file_path):\n",
    "    dir_list = os.listdir(file_path)\n",
    "    if not dir_list:\n",
    "        return\n",
    "    else:\n",
    "        dir_list = sorted(dir_list, key=lambda x: os.path.getmtime(os.path.join(file_path, x)))\n",
    "    return dir_list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    }
   ],
   "source": [
    "from keras.preprocessing import sequence\n",
    "def generate_train(batch_size):\n",
    "    print('\\n*********************************generate_train()*********************************')\n",
    "    steps=0\n",
    "    eng_ = eng\n",
    "    cns_ = cns\n",
    "    while True:\n",
    "        batch_cns_o = cns_o[steps:steps+batch_size]\n",
    "        batch_eng = eng_[steps:steps+batch_size]\n",
    "        batch_cns = cns_[steps:steps+batch_size]\n",
    "        outs = np.zeros([batch_size, maxLen, vocab_size], dtype='float32')\n",
    "        for pos, i in enumerate(batch_cns_o):\n",
    "            for pos_, j in enumerate(i):\n",
    "                if pos_ > 20:\n",
    "                    print(i)\n",
    "                outs[pos, pos_, j] = 1 # one-hot\n",
    "        yield [batch_eng, batch_cns], outs\n",
    "        steps += batch_size\n",
    "        if steps == 100000:\n",
    "            steps = 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From c:\\users\\王嘉意\\appdata\\local\\programs\\python\\python36\\lib\\site-packages\\tensorflow\\python\\ops\\math_ops.py:3066: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use tf.cast instead.\n",
      "WARNING:tensorflow:From c:\\users\\王嘉意\\appdata\\local\\programs\\python\\python36\\lib\\site-packages\\tensorflow\\python\\ops\\math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Deprecated in favor of operator or tf.math.divide.\n",
      "Epoch 1/200\n",
      "\n",
      "*********************************generate_train()*********************************\n",
      "  19/1000 [..............................] - ETA: 26:55 - loss: 5.9047"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-4-ab56f6fa99e9>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m    116\u001b[0m                     \u001b[0muse_multiprocessing\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mFalse\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    117\u001b[0m                     \u001b[0mshuffle\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mFalse\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 118\u001b[1;33m                     \u001b[0minitial_epoch\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0minitial_epoch_\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    119\u001b[0m                     )\n\u001b[0;32m    120\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\AppData\\Roaming\\Python\\Python36\\site-packages\\keras\\legacy\\interfaces.py\u001b[0m in \u001b[0;36mwrapper\u001b[1;34m(*args, **kwargs)\u001b[0m\n\u001b[0;32m     89\u001b[0m                 warnings.warn('Update your `' + object_name + '` call to the ' +\n\u001b[0;32m     90\u001b[0m                               'Keras 2 API: ' + signature, stacklevel=2)\n\u001b[1;32m---> 91\u001b[1;33m             \u001b[1;32mreturn\u001b[0m \u001b[0mfunc\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     92\u001b[0m         \u001b[0mwrapper\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_original_function\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mfunc\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     93\u001b[0m         \u001b[1;32mreturn\u001b[0m \u001b[0mwrapper\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\AppData\\Roaming\\Python\\Python36\\site-packages\\keras\\engine\\training.py\u001b[0m in \u001b[0;36mfit_generator\u001b[1;34m(self, generator, steps_per_epoch, epochs, verbose, callbacks, validation_data, validation_steps, class_weight, max_queue_size, workers, use_multiprocessing, shuffle, initial_epoch)\u001b[0m\n\u001b[0;32m   1416\u001b[0m             \u001b[0muse_multiprocessing\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0muse_multiprocessing\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1417\u001b[0m             \u001b[0mshuffle\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mshuffle\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1418\u001b[1;33m             initial_epoch=initial_epoch)\n\u001b[0m\u001b[0;32m   1419\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1420\u001b[0m     \u001b[1;33m@\u001b[0m\u001b[0minterfaces\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlegacy_generator_methods_support\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\AppData\\Roaming\\Python\\Python36\\site-packages\\keras\\engine\\training_generator.py\u001b[0m in \u001b[0;36mfit_generator\u001b[1;34m(model, generator, steps_per_epoch, epochs, verbose, callbacks, validation_data, validation_steps, class_weight, max_queue_size, workers, use_multiprocessing, shuffle, initial_epoch)\u001b[0m\n\u001b[0;32m    215\u001b[0m                 outs = model.train_on_batch(x, y,\n\u001b[0;32m    216\u001b[0m                                             \u001b[0msample_weight\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0msample_weight\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 217\u001b[1;33m                                             class_weight=class_weight)\n\u001b[0m\u001b[0;32m    218\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    219\u001b[0m                 \u001b[0mouts\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mto_list\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mouts\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\AppData\\Roaming\\Python\\Python36\\site-packages\\keras\\engine\\training.py\u001b[0m in \u001b[0;36mtrain_on_batch\u001b[1;34m(self, x, y, sample_weight, class_weight)\u001b[0m\n\u001b[0;32m   1215\u001b[0m             \u001b[0mins\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0my\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0msample_weights\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1216\u001b[0m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_make_train_function\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1217\u001b[1;33m         \u001b[0moutputs\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtrain_function\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mins\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1218\u001b[0m         \u001b[1;32mreturn\u001b[0m \u001b[0munpack_singleton\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0moutputs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1219\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\AppData\\Roaming\\Python\\Python36\\site-packages\\keras\\backend\\tensorflow_backend.py\u001b[0m in \u001b[0;36m__call__\u001b[1;34m(self, inputs)\u001b[0m\n\u001b[0;32m   2713\u001b[0m                 \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_legacy_call\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minputs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   2714\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 2715\u001b[1;33m             \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_call\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minputs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   2716\u001b[0m         \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   2717\u001b[0m             \u001b[1;32mif\u001b[0m \u001b[0mpy_any\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mis_tensor\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mx\u001b[0m \u001b[1;32min\u001b[0m \u001b[0minputs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\AppData\\Roaming\\Python\\Python36\\site-packages\\keras\\backend\\tensorflow_backend.py\u001b[0m in \u001b[0;36m_call\u001b[1;34m(self, inputs)\u001b[0m\n\u001b[0;32m   2673\u001b[0m             \u001b[0mfetched\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_callable_fn\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0marray_vals\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mrun_metadata\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrun_metadata\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   2674\u001b[0m         \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 2675\u001b[1;33m             \u001b[0mfetched\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_callable_fn\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0marray_vals\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   2676\u001b[0m         \u001b[1;32mreturn\u001b[0m \u001b[0mfetched\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0moutputs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   2677\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mc:\\users\\王嘉意\\appdata\\local\\programs\\python\\python36\\lib\\site-packages\\tensorflow\\python\\client\\session.py\u001b[0m in \u001b[0;36m__call__\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m   1437\u001b[0m           ret = tf_session.TF_SessionRunCallable(\n\u001b[0;32m   1438\u001b[0m               \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_session\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_session\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_handle\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mstatus\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1439\u001b[1;33m               run_metadata_ptr)\n\u001b[0m\u001b[0;32m   1440\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mrun_metadata\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1441\u001b[0m           \u001b[0mproto_data\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtf_session\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTF_GetBuffer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mrun_metadata_ptr\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "from keras.layers import Embedding\n",
    "from keras.layers import Input, Dense, LSTM, TimeDistributed, Bidirectional, Dropout, Concatenate, RepeatVector, Activation, Dot\n",
    "from keras.layers import concatenate, dot                    \n",
    "from keras.models import Model\n",
    "from keras.utils import plot_model\n",
    "from keras.callbacks import ModelCheckpoint, TensorBoard,ReduceLROnPlateau\n",
    "from keras.initializers import TruncatedNormal\n",
    "import pydot\n",
    "import os, re\n",
    "truncatednormal = TruncatedNormal(mean=0.0, stddev=0.05)\n",
    "embed_layer = Embedding(input_dim=vocab_size, \n",
    "                        output_dim=100, \n",
    "                        mask_zero=True,\n",
    "                        input_length=None,\n",
    "                        embeddings_initializer= truncatednormal)\n",
    "LSTM_encoder = LSTM(256,\n",
    "                      return_sequences=True,\n",
    "                      return_state=True,\n",
    "#                       activation='relu',\n",
    "#                       dropout=0.25,\n",
    "#                       recurrent_dropout=0.1,\n",
    "                      kernel_initializer= 'lecun_uniform',\n",
    "                      name='encoder_lstm'\n",
    "                        )\n",
    "LSTM_decoder = LSTM(256, \n",
    "                    return_sequences=True, \n",
    "                    return_state=True, \n",
    "#                     activation = 'relu',\n",
    "#                     dropout=0.25, \n",
    "#                     recurrent_dropout=0.1,\n",
    "                    kernel_initializer= 'lecun_uniform',\n",
    "                    name='decoder_lstm'\n",
    "                   )\n",
    "#encoder输入 与 decoder输入\n",
    "input_eng = Input(shape=(None, ), dtype='int32', name='input_eng')\n",
    "input_cns = Input(shape=(None, ), dtype='int32', name='input_cns')\n",
    "\n",
    "input_eng_embed = embed_layer(input_eng)\n",
    "input_cns_embed = embed_layer(input_cns)\n",
    "\n",
    "encoder_lstm, eng_h, eng_c = LSTM_encoder(input_eng_embed)\n",
    "\n",
    "decoder_lstm, _, _ = LSTM_decoder(input_cns_embed, \n",
    "                                  initial_state=[eng_h, eng_c])\n",
    "\n",
    "attention = dot([decoder_lstm, encoder_lstm], axes=[2, 2])\n",
    "attention = Activation('softmax')(attention)\n",
    "context = dot([attention, encoder_lstm], axes=[2,1])\n",
    "decoder_combined_context = concatenate([context, decoder_lstm])\n",
    "\n",
    "# output = dense1(decoder_combined_context)\n",
    "# output = dense2(Dropout(0.5)(output))\n",
    "\n",
    "# Has another weight + tanh layer as described in equation (5) of the paper\n",
    "decoder_dense1 = TimeDistributed(Dense(128,activation=\"tanh\"))\n",
    "decoder_dense2 = TimeDistributed(Dense(vocab_size,activation=\"softmax\"))\n",
    "output = decoder_dense1(decoder_combined_context) # equation (5) of the paper\n",
    "output = decoder_dense2(output) # equation (6) of the paper\n",
    "\n",
    "model = Model([input_eng, input_cns], output)\n",
    "\n",
    "model.compile(optimizer='rmsprop', loss='categorical_crossentropy')\n",
    "\n",
    "filepath = main_path + \"modles/W-\" + \"-{epoch:3d}-{loss:.4f}-.h5\"\n",
    "checkpoint = ModelCheckpoint(filepath,\n",
    "                             monitor='loss',\n",
    "                             verbose=1,\n",
    "                             save_best_only=True,\n",
    "                             mode='min',\n",
    "                             period=1,\n",
    "                             save_weights_only=True\n",
    "                             )\n",
    "reduce_lr = ReduceLROnPlateau(monitor='loss', \n",
    "                              factor=0.2, \n",
    "                              patience=2, \n",
    "                              verbose=1, \n",
    "                              mode='min', \n",
    "                              min_delta=0.0001, \n",
    "                              cooldown=0, \n",
    "                              min_lr=0\n",
    "                              )\n",
    "tensorboard = TensorBoard(log_dir=main_path + 'logs', \n",
    "#                           histogram_freq=0, \n",
    "                          batch_size=100\n",
    "#                           write_graph=True, \n",
    "#                           write_grads=True, \n",
    "#                           write_images=True, \n",
    "#                           embeddings_freq=0, \n",
    "#                           embeddings_layer_names=None, \n",
    "#                           embeddings_metadata=None, \n",
    "#                           embeddings_data=None, \n",
    "#                           update_freq='epoch'\n",
    "                         )\n",
    "callbacks_list = [checkpoint, reduce_lr, tensorboard]\n",
    "\n",
    "initial_epoch_=0\n",
    "# file_list = os.listdir(main_path + 'modles/')\n",
    "# if len(file_list) > 0:\n",
    "#     epoch_list = get_file_list(main_path + 'modles/')\n",
    "#     epoch_last = epoch_list[-1]\n",
    "#     model.load_weights(main_path + 'modles/' + epoch_last)\n",
    "#     print(\"**********checkpoint_loaded: \", epoch_last)\n",
    "#     initial_epoch_ = int(epoch_last.split('-')[2]) - 1\n",
    "#     print('**********Begin from epoch: ', str(initial_epoch_))\n",
    "\n",
    "model.fit_generator(generate_train(batch_size=100), \n",
    "                    steps_per_epoch=200, # (total samples) / batch_size 90000/100 = 900\n",
    "                    epochs=200, \n",
    "                    verbose=1, \n",
    "#                     callbacks=callbacks_list, \n",
    "#                     validation_data=generate_test(batch_size=100), \n",
    "#                     validation_steps=200, # 10000/100 = 100\n",
    "                    class_weight=None, \n",
    "                    max_queue_size=5, \n",
    "                    workers=1, \n",
    "                    use_multiprocessing=False, \n",
    "                    shuffle=False, \n",
    "                    initial_epoch=initial_epoch_\n",
    "                    )\n",
    "\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
